package com.cnbm.wcsbasic.protocol.netty.io;


import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import com.cnbm.wcsbasic.protocol.netty.io.common.Package;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Desc: ""
 * @Author: caixiang
 * @DATE: 2024-06-05 14:17
 */
public class ReconnectAndHeartBeatHandler extends ChannelInboundHandlerAdapter {

    private static final Logger logger = LoggerFactory.getLogger("DCLOGGER");

    private FGClient client;

    public ReconnectAndHeartBeatHandler(FGClient client) {
        this.client = client;
    }
    //这个心跳报文其实是固定的，因为每个
    private static byte[] heartBeatBytes = {0, 0, 0, 0, 0, 6, 1, 3, 0, 0, 0, 1};
    private static Package heartBeat = new Package(heartBeatBytes,"0-0");


    /**
     * todo 心跳应该写到具体协议里面
     * decs: 重写IdleStateEvent 实现，用于心跳信号
     *
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.ALL_IDLE){
                ctx.channel().writeAndFlush(heartBeat);
                //能输出这个日志 ，代表writeAndFlush 没问题，不然 就被channelInactive拦截了
                logger.info("    [ ReconnectAndHeartBeatHandler ]  [   "+client.getName()+"   " +client.getHost()+"   ]    ( heartbeating )   Communication succeeded ");
            }
        }
    }

    /**
     * channel 处于不活动状态时调用
     * desc:
     *     1. 当io异常的时候，会直接到这里，比如心跳断开，网络断开，设备断电,或者重试3次任然失败 ....
     *     2. 当某个地方close()后入到这里，别的地方再close channel 是不会重复进入到这里的。
     * @param ctx 上下文对象, 含有通道channel，管道pipeline
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String info = "    [ ReconnectAndHeartBeatHandler ]  [   "+client.getName() +"   "+ client.getHost() + "   ]    ( Exception )   ChannelInactive Be Caught,  Try To Reconnect ";
        logger.info(info);
        client.setIsOnline(false);
        this.client.connect();

        //super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        String info = "    [ ReconnectAndHeartBeatHandler ]  [   "+client.getName() +"   "+ client.getHost() + "   ]    ( Exception )   exceptionCaught Be Caught, Err Reason："+cause.getMessage();
        logger.error(info);
        client.setIsOnline(false);
        //这里调用了close方法 会出发 上面的 channelInactive事件
        ctx.close();
    }

}
